package com.yuma.tingshu.account.service.impl;

import ch.qos.logback.classic.spi.EventArgUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuma.tingshu.account.mapper.UserAccountDetailMapper;
import com.yuma.tingshu.account.mapper.UserAccountMapper;
import com.yuma.tingshu.account.service.UserAccountService;
import com.yuma.tingshu.common.constant.RedisConstant;
import com.yuma.tingshu.common.constant.SystemConstant;
import com.yuma.tingshu.common.execption.YumaException;
import com.yuma.tingshu.common.result.ResultCodeEnum;
import com.yuma.tingshu.common.util.AuthContextHolder;
import com.yuma.tingshu.model.account.UserAccount;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuma.tingshu.model.account.UserAccountDetail;
import com.yuma.tingshu.vo.account.AccountLockResultVo;
import com.yuma.tingshu.vo.account.AccountLockVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements UserAccountService {

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private UserAccountDetailMapper userAccountDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Transactional
    @Override
    public void saveAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setUserId(userId);
        this.save(userAccount);
    }

    // 本地事务
    @Transactional
    @Override
    public void initAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setUserId(userId);
        this.save(userAccount);
    }

    @Transactional
    @Override
    public AccountLockResultVo checkLock(AccountLockVo accountLockVo) {
        // 1.判空
        if (accountLockVo == null) {
            throw new YumaException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
        }
        // 2.幂等性处理
		// 2.1 从Redis中查询是否有锁定对象，有就直接返回锁定对象
		String lockKey =  RedisConstant.ACCOUNT_LOCK_INFO_PREFIX + accountLockVo.getOrderNo();
		AccountLockResultVo accountLockResultVo = (AccountLockResultVo) redisTemplate.opsForValue().get(lockKey);
		if (accountLockResultVo != null) {
            return accountLockResultVo;
        }
		// 2.2 没有锁定对象继续(锁定余额足够的用户)
        // 3.查询余额是否够用
        UserAccount userAccount = userAccountMapper.check(AuthContextHolder.getUserId(), accountLockVo.getAmount());
        // 3.1不够用就抛异常
        if (userAccount == null) {
            throw new YumaException(ResultCodeEnum.ACCOUNT_LESS);
        }
        // 3.2余额够用就锁定余额
        int updateRow = userAccountMapper.lock(userAccount.getId(), accountLockVo.getAmount());
        if (updateRow == 1) {
            // 4.写入user_account_detail表
            UserAccountDetail userAccountDetail = new UserAccountDetail()
                    .setUserId(accountLockVo.getUserId())
                    .setTitle("订单余额锁定")
                    .setTradeType(SystemConstant.ACCOUNT_TRADE_TYPE_LOCK)
                    .setAmount(accountLockVo.getAmount())
                    .setOrderNo(accountLockVo.getOrderNo());
            this.userAccountDetailMapper.insert(userAccountDetail);
            // 5.创建锁定对象到缓存中一份
            accountLockResultVo = new AccountLockResultVo();
            accountLockResultVo.setUserId(accountLockVo.getUserId());
            accountLockResultVo.setAmount(accountLockVo.getAmount());
            accountLockResultVo.setContent("账户锁定");
            this.redisTemplate.opsForValue().set(lockKey, accountLockResultVo, RedisConstant.CACHE_TIMEOUT, TimeUnit.SECONDS);
            // 6.返回锁定对象
            return accountLockResultVo;
        } else {
            throw new YumaException(ResultCodeEnum.ACCOUNT_LOCK_ERROR);
        }
    }

    @Override
    public Page<UserAccountDetail> findUserRechargePage(Integer page, Integer limit) {
        return userAccountDetailMapper.selectPage(new Page<>(page, limit), new LambdaQueryWrapper<UserAccountDetail>()
                .eq(UserAccountDetail::getUserId, AuthContextHolder.getUserId())
                .eq(UserAccountDetail::getTradeType, SystemConstant.ACCOUNT_TRADE_TYPE_DEPOSIT)
                .orderByDesc(UserAccountDetail::getCreateTime));
    }

    @Override
    public Page<UserAccountDetail> findAccountDetails(String accountTradeTypeMinus, Integer page, Integer limit) {
        return userAccountDetailMapper.selectPage(new Page<UserAccountDetail>(page, limit),
                new LambdaQueryWrapper<UserAccountDetail>()
                        .eq(UserAccountDetail::getTradeType, accountTradeTypeMinus)
                        .eq(UserAccountDetail::getUserId, AuthContextHolder.getUserId())
                        .orderByDesc(UserAccountDetail::getCreateTime));
    }
}
